home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / ms_sh21s.zip / SH210 / SRC / SH11.C < prev    next >
C/C++ Source or Header  |  1992-12-14  |  21KB  |  949 lines

  1. /*
  2.  * MS-DOS SHELL - Maths Evaluation Functions
  3.  *
  4.  * MS-DOS SHELL - Copyright (c) 1990,1,2 Data Logic Limited and Paul Falstad
  5.  *
  6.  * This code is based on (in part) the shell program written by Paul Falstad
  7.  * and is subject to the following copyright restrictions:
  8.  *
  9.  * 1.  Redistribution and use in source and binary forms are permitted
  10.  *     provided that the above copyright notice is duplicated in the
  11.  *     source form and the copyright notice in file sh6.c is displayed
  12.  *     on entry to the program.
  13.  *
  14.  * 2.  The sources (or parts thereof) or objects generated from the sources
  15.  *     (or parts of sources) cannot be sold under any circumstances.
  16.  *
  17.  * This source is based on the math.c (mathematical expression evaluation) from
  18.  * the Z shell.  Z Shell is free software, under the GNU license.  This
  19.  * code is included in this program under the provisions of paragraph 8 of
  20.  * GNU GENERAL PUBLIC LICENSE, Version 1, February 1989.  I contacted Paul
  21.  * via E-Mail, and he is happy to allow the source to be included in this
  22.  * program.
  23.  *
  24.  *    $Header: /usr/users/istewart/src/shell/sh2.1/RCS/sh11.c,v 2.2 1992/11/06 10:03:44 istewart Exp $
  25.  *
  26.  *    $Log: sh11.c,v $
  27.  *    Revision 2.2  1992/11/06  10:03:44  istewart
  28.  *    214 Beta test updates
  29.  *
  30.  *    Revision 2.2  1992/11/06  10:03:44  istewart
  31.  *    214 Beta test updates
  32.  *
  33.  *    Revision 2.1  1992/07/10  10:52:48  istewart
  34.  *    211 Beta updates
  35.  *
  36.  *    Revision 2.0  1992/04/13  17:39:09  Ian_Stewartson
  37.  *    MS-Shell 2.0 Baseline release
  38.  *
  39.  */
  40.  
  41. #include <sys/types.h>
  42. #include <sys/stat.h>
  43. #include <stdio.h>
  44. #include <signal.h>
  45. #include <setjmp.h>
  46. #include <ctype.h>
  47. #include <string.h>
  48. #include <unistd.h>
  49. #include <stdlib.h>
  50. #include <limits.h>
  51. #ifdef OS2
  52. #define INCL_DOSSESMGR
  53. #include <os2.h>
  54. #else
  55. #include <dos.h>
  56. #endif
  57. #include "sh.h"
  58.  
  59. #define STACK_SIZE    100        /* Stack size            */
  60. #define MAX_PRECEDENCE    15
  61. #define MAX_VARIABLES    32        /* Number of user variables    */
  62.  
  63. /*
  64.  * Some macros
  65.  */
  66.  
  67. #define POP_2_VALUES()        b = stack[StackPointer--].val;    \
  68.                   a = stack[StackPointer--].val;
  69.  
  70. #define PUSH_VALUE_ON_STACK(X)    PushOnToStack ((long)(X), -1);
  71. #define SET_VALUE_ON_STACK(X)    PushOnToStack (SetVariableValue    \
  72.                         (lv, (long)(X)), lv);
  73.  
  74. /* the value stack */
  75.  
  76. static int    LastToken;        /* Last token            */
  77. static int    StackPointer = -1;    /* Stack pointer        */
  78.  
  79. static struct MathsStack {
  80.     int        lval;
  81.     long    val;
  82. } stack[STACK_SIZE];
  83.  
  84. static int    NumberOfVariables = 0;        /* Number of variables    */
  85. static char    *ListOfVariableNames[MAX_VARIABLES];
  86. static char    *CStringp;            /* Current position    */
  87. static long    yyval;
  88. static int    yylval;
  89. static int    JustParsing = 0;        /* Nonzero means we are    */
  90.                         /* not evaluating, just    */
  91.                         /* parsing        */
  92. static bool    RecogniseUnaryOperator = TRUE;    /* TRUE means recognize    */
  93.                         /* unary plus, minus,    */
  94.                         /* etc.            */
  95.  
  96. /*
  97.  * LEFT_RIGHT_A = left-to-right associativity
  98.  * RIGHT_LEFT_A = right-to-left associativity
  99.  * BOOL_A = short-circuiting boolean
  100.  */
  101.  
  102. #define LEFT_RIGHT_A            0
  103. #define RIGHT_LEFT_A            1
  104. #define BOOL_A                2
  105.  
  106. #define OP_OPEN_PAR            0
  107. #define OP_CLOSE_PAR            1
  108. #define OP_NOT                2
  109. #define OP_COMPLEMENT            3
  110. #define OP_POST_PLUS            4
  111. #define OP_POST_MINUS            5
  112. #define OP_UNARY_PLUS            6
  113. #define OP_UNARY_MINUS            7
  114. #define OP_BINARY_AND_EQUALS        8
  115. #define OP_BINARY_XOR_EQUALS        9
  116. #define OP_BINARY_OR_EQUALS        10
  117. #define OP_MULTIPLY            11
  118. #define OP_DIVIDE            12
  119. #define OP_MODULUS            13
  120. #define OP_PLUS                14
  121. #define OP_MINUS            15
  122. #define OP_SHIFT_LEFT            16
  123. #define OP_SHIFT_RIGHT            17
  124. #define OP_LESS                18
  125. #define OP_LESS_EQUALS            19
  126. #define OP_GREATER            20
  127. #define OP_GREATER_EQUALS        21
  128. #define OP_EQUALS            22
  129. #define OP_NOT_EQUALS            23
  130. #define OP_LOGICAL_AND_EQUALS        24
  131. #define OP_LOGICAL_OR_EQUALS        25
  132. #define OP_LOGICAL_XOR_EQUALS        26
  133. #define OP_QUESTION_MARK        27
  134. #define OP_COLON            28
  135. #define OP_SET                29
  136. #define OP_PLUS_EQUAL            30
  137. #define OP_MINUS_EQUAL            31
  138. #define OP_MULTIPLY_EQUAL        32
  139. #define OP_DIVIDE_EQUAL            33
  140. #define OP_MODULUS_EQUAL        34
  141. #define OP_BINARY_AND_SET        35
  142. #define OP_BINARY_XOR_SET        36
  143. #define OP_BINARY_OR_SET        37
  144. #define OP_SHIFT_LEFT_EQUAL        38
  145. #define OP_SHIFT_RIGHT_EQUAL        39
  146. #define OP_LOGICAL_AND_SET        40
  147. #define OP_LOGICAL_OR_SET        41
  148. #define OP_LOGICAL_XOR_SET        42
  149. #define OP_COMMA            43
  150. #define OP_END_OF_INPUT            44
  151. #define OP_PRE_PLUS            45
  152. #define OP_PRE_MINUS            46
  153. #define OP_NUMERIC_VALUE        47
  154. #define OP_VARIABLE            48
  155. #define MAX_OPERATORS            49
  156.  
  157. /* precedences */
  158.  
  159. static struct Operators {
  160.     int        Precedences;        /* Operator Precedences        */
  161.     int        Type;            /* Operator Association        */
  162. } Operators [MAX_OPERATORS] = {
  163.     {   1,    LEFT_RIGHT_A },        /* 0 - (            */
  164.     { 137,    LEFT_RIGHT_A },        /* 1 - )            */
  165.     {   2,    RIGHT_LEFT_A },        /* 2 - !            */
  166.     {   2,    RIGHT_LEFT_A },        /* 3 - ~            */
  167.     {   2,    RIGHT_LEFT_A },        /* 4 - x++            */
  168.     {   2,    RIGHT_LEFT_A },        /* 5 - x--            */
  169.     {   2,    RIGHT_LEFT_A },        /* 6 - +            */
  170.     {   2,    RIGHT_LEFT_A },        /* 7 - -            */
  171.     {   4,    LEFT_RIGHT_A },        /* 8 - &            */
  172.     {   5,    LEFT_RIGHT_A },        /* 9 - ^            */
  173.     {   6,    LEFT_RIGHT_A },        /* 10 - |            */
  174.     {   7,    LEFT_RIGHT_A },        /* 11 - *            */
  175.     {   7,    LEFT_RIGHT_A },        /* 12 - /            */
  176.     {   7,    LEFT_RIGHT_A },        /* 13 - %            */
  177.     {   8,    LEFT_RIGHT_A },        /* 14 - +            */
  178.     {   8,    LEFT_RIGHT_A },        /* 15 - -            */
  179.     {   3,    LEFT_RIGHT_A },        /* 16 - <            */
  180.     {   3,    LEFT_RIGHT_A },        /* 17 - >            */
  181.     {   9,    LEFT_RIGHT_A },        /* 18 - < (less than)        */
  182.     {   9,    LEFT_RIGHT_A },        /* 19 - <= (less than equal)    */
  183.     {   9,    LEFT_RIGHT_A },        /* 20 - > (greater than)    */
  184.     {   9,    LEFT_RIGHT_A },        /* 21 - >= (greater than equal) */
  185.     {  10,    LEFT_RIGHT_A },        /* 22 - ==            */
  186.     {  10,    LEFT_RIGHT_A },        /* 23 - !=            */
  187.     {  11,    BOOL_A },        /* 24 - &&            */
  188.     {  12,    BOOL_A },        /* 25 - ||            */
  189.     {  12,    LEFT_RIGHT_A },        /* 26 - ^^            */
  190.     {  13,    RIGHT_LEFT_A },        /* 27 - ?            */
  191.     {  13,    RIGHT_LEFT_A },        /* 28 - :            */
  192.     {  14,    RIGHT_LEFT_A },        /* 29 - =             */
  193.     {  14,    RIGHT_LEFT_A },        /* 30 - +=            */
  194.     {  14,    RIGHT_LEFT_A },        /* 31 - -=            */
  195.     {  14,    RIGHT_LEFT_A },        /* 32 - *=            */
  196.     {  14,    RIGHT_LEFT_A },        /* 33 - /=            */
  197.     {  14,    RIGHT_LEFT_A },        /* 34 - %=            */
  198.     {  14,    RIGHT_LEFT_A },        /* 35 - &=            */
  199.     {  14,    RIGHT_LEFT_A },        /* 36 - ^=            */
  200.     {  14,    RIGHT_LEFT_A },        /* 37 - |=            */
  201.     {  14,    RIGHT_LEFT_A },        /* 38 - <=            */
  202.     {  14,    RIGHT_LEFT_A },        /* 39 - >=            */
  203.     {  14,    BOOL_A },        /* 40 - &&=            */
  204.     {  14,    BOOL_A },        /* 41 - ||=            */
  205.     {  14,    RIGHT_LEFT_A },        /* 42 - ^^=            */
  206.     {  15,    RIGHT_LEFT_A },        /* 43 - ,            */
  207.     { 200,    RIGHT_LEFT_A },        /* 44 - End of input        */
  208.     {   2,    RIGHT_LEFT_A },        /* 45 - ++x            */
  209.     {   2,    RIGHT_LEFT_A },        /* 46 - --x            */
  210.     {   0,    LEFT_RIGHT_A },        /* 47 - Numeric value        */
  211.     {   0,    LEFT_RIGHT_A }        /* 48 - Variable        */
  212. };
  213.  
  214.  
  215.  
  216. /*
  217.  * Functions
  218.  */
  219.  
  220. static void near    PushOnToStack (long, int);
  221. static long near    SetVariableValue (int, long);
  222. static bool near    CheckNotZero (long);
  223. static void near    ProcessOperator (int);
  224. static void near    ProcessBinaryOperator (int);
  225. static void near    ParseMathsExpression (int);
  226. static int near        MathsLexicalAnalyser (void);
  227. static int near        DecideSingleOperator (int, int);
  228. static int near        DecideDoubleOperator (char, int, int, int, int);
  229. static int near        DecideSignOperator (char, int, int, int, int, int);
  230.  
  231. /*
  232.  * Analyse the string
  233.  */
  234.  
  235. static int near MathsLexicalAnalyser (void)
  236. {
  237.     while (TRUE)
  238.     {
  239.     switch (*(CStringp++))
  240.     {
  241.         case '+':
  242.         return DecideSignOperator ('+', OP_PRE_PLUS,
  243.                         OP_POST_PLUS,
  244.                         OP_PLUS_EQUAL,
  245.                         OP_UNARY_PLUS,
  246.                         OP_PLUS);
  247.  
  248.         case '-':
  249.         return DecideSignOperator ('+', OP_PRE_MINUS,
  250.                         OP_POST_MINUS,
  251.                         OP_MINUS_EQUAL,
  252.                         OP_UNARY_MINUS,
  253.                         OP_MINUS);
  254.  
  255.         case CHAR_OPEN_PARATHENSIS:
  256.         RecogniseUnaryOperator = TRUE;
  257.         return OP_OPEN_PAR;
  258.  
  259.         case CHAR_CLOSE_PARATHENSIS:
  260.         return OP_CLOSE_PAR;
  261.  
  262.         case '!':
  263.         if (*CStringp == '=')
  264.         {
  265.             RecogniseUnaryOperator = TRUE;
  266.             CStringp++;
  267.             return OP_NOT_EQUALS;
  268.         }
  269.  
  270.         return OP_NOT;
  271.  
  272.         case '~':
  273.         return OP_COMPLEMENT;
  274.  
  275.         case '&':
  276.         return DecideDoubleOperator ('&', OP_LOGICAL_AND_SET,
  277.                           OP_BINARY_AND_SET,
  278.                           OP_LOGICAL_AND_EQUALS,
  279.                           OP_BINARY_AND_EQUALS);
  280.  
  281.         case '|':
  282.         return DecideDoubleOperator ('|', OP_LOGICAL_OR_SET,
  283.                           OP_BINARY_OR_SET,
  284.                           OP_LOGICAL_OR_EQUALS,
  285.                           OP_BINARY_OR_EQUALS);
  286.  
  287.         case CHAR_XOR:
  288.         return DecideDoubleOperator (CHAR_XOR, OP_LOGICAL_XOR_SET,
  289.                           OP_BINARY_XOR_SET,
  290.                           OP_LOGICAL_XOR_EQUALS,
  291.                           OP_BINARY_XOR_EQUALS);
  292.  
  293.         case '*':
  294.         return DecideSingleOperator (OP_MULTIPLY_EQUAL, OP_MULTIPLY);
  295.  
  296.         case '/':
  297.         return DecideSingleOperator (OP_DIVIDE_EQUAL, OP_DIVIDE);
  298.  
  299.         case '%':
  300.         return DecideSingleOperator (OP_MODULUS_EQUAL, OP_MODULUS);
  301.  
  302.         case '<':
  303.         return DecideDoubleOperator ('<', OP_SHIFT_LEFT_EQUAL,
  304.                           OP_LESS_EQUALS,
  305.                           OP_SHIFT_LEFT,
  306.                           OP_LESS);
  307.  
  308.         case '>':
  309.         return DecideDoubleOperator ('>', OP_SHIFT_RIGHT_EQUAL,
  310.                           OP_GREATER_EQUALS,
  311.                           OP_SHIFT_RIGHT,
  312.                           OP_GREATER);
  313.  
  314.         case '=':
  315.         return DecideSingleOperator (OP_EQUALS, OP_SET);
  316.  
  317.         case '?':
  318.         RecogniseUnaryOperator = TRUE;
  319.         return OP_QUESTION_MARK;
  320.  
  321.         case ':':
  322.         RecogniseUnaryOperator = TRUE;
  323.         return OP_COLON;
  324.  
  325.         case ',':
  326.         RecogniseUnaryOperator = TRUE;
  327.         return OP_COMMA;
  328.  
  329.         case '\0':
  330.         RecogniseUnaryOperator = TRUE;
  331.         CStringp--;
  332.         return OP_END_OF_INPUT;
  333.  
  334.         case CHAR_OPEN_BRACKETS:
  335.         RecogniseUnaryOperator = FALSE;
  336.  
  337.         LastNumberBase = (int)strtol (CStringp, &CStringp, 10);
  338.  
  339.         if (*CStringp == CHAR_CLOSE_BRACKETS)
  340.             CStringp++;
  341.  
  342.         yyval = strtol (CStringp, &CStringp, LastNumberBase);
  343.  
  344.         return OP_NUMERIC_VALUE;
  345.  
  346.         default:
  347.         if (isspace (*(CStringp - 1)))
  348.             break;
  349.  
  350. /* Check for a numeric value */
  351.  
  352.         if (isdigit (*--CStringp))
  353.         {
  354.             RecogniseUnaryOperator = FALSE;
  355.             yyval = strtol (CStringp, &CStringp, 10);
  356.             return OP_NUMERIC_VALUE;
  357.         }
  358.  
  359. /* Check for a variable */
  360.  
  361.         if (isalpha (*CStringp) || *CStringp == '$')
  362.         {
  363.             char    *p, q;
  364.  
  365.             if (*CStringp == '$')
  366.             CStringp++;
  367.  
  368.             p = CStringp;
  369.  
  370.             if (NumberOfVariables == MAX_VARIABLES)
  371.             {
  372.             ShellErrorMessage ("too many identifiers");
  373.             ExpansionErrorDetected = TRUE;
  374.             return OP_END_OF_INPUT;
  375.             }
  376.  
  377.             RecogniseUnaryOperator = FALSE;
  378.  
  379.             while (isalpha (*++CStringp))
  380.             continue;
  381.  
  382. /* Save the variable name */
  383.  
  384.             q = *CStringp;
  385.             *CStringp = '\0';
  386.             ListOfVariableNames[yylval = NumberOfVariables++] =
  387.                     StringCopy (p);
  388.             *CStringp = q;
  389.             return OP_VARIABLE;
  390.         }
  391.  
  392.         return OP_END_OF_INPUT;
  393.     }
  394.     }
  395. }
  396.  
  397. /*
  398.  * Stick variable on the stack
  399.  */
  400.  
  401. static void near PushOnToStack (long val, int lval)
  402. {
  403.     if (StackPointer == STACK_SIZE - 1)
  404.     {
  405.     ShellErrorMessage ("stack overflow");
  406.     ExpansionErrorDetected = TRUE;
  407.     }
  408.  
  409.     else
  410.     StackPointer++;
  411.  
  412.     stack[StackPointer].val = val;
  413.     stack[StackPointer].lval = lval;
  414. }
  415.  
  416. /*
  417.  * Get a variable value
  418.  */
  419.  
  420. static long near SetVariableValue (int s, long v)
  421. {
  422.     if (s == -1 || s >= NumberOfVariables)
  423.     {
  424.     ExpansionErrorDetected = TRUE;
  425.     ShellErrorMessage ("lvalue required");
  426.     return 0;
  427.     }
  428.  
  429.     if (JustParsing)
  430.     return v;
  431.  
  432.     SetVariableFromNumeric (ListOfVariableNames[s], v);
  433.     return v;
  434. }
  435.  
  436. /*
  437.  * Check for Division by zero
  438.  */
  439.  
  440. static bool near CheckNotZero (long a)
  441. {
  442.     if (a)
  443.     return TRUE;
  444.  
  445.     ShellErrorMessage ("division by zero");
  446.     ExpansionErrorDetected = TRUE;
  447.     return FALSE;
  448. }
  449.  
  450. /*
  451.  * Process operator
  452.  */
  453.  
  454. static void near ProcessOperator (int what)
  455. {
  456.     long    a, b, c;
  457.     int        lv;
  458.  
  459.     if (StackPointer < 0)
  460.     {
  461.     ShellErrorMessage ("bad math expression - stack empty");
  462.     ExpansionErrorDetected = TRUE;
  463.     return;
  464.     }
  465.  
  466.     switch (what)
  467.     {
  468.     case OP_NOT:
  469.         stack[StackPointer].val = !stack[StackPointer].val;
  470.         stack[StackPointer].lval= -1;
  471.         break;
  472.  
  473.     case OP_COMPLEMENT:
  474.         stack[StackPointer].val = ~stack[StackPointer].val;
  475.         stack[StackPointer].lval= -1;
  476.         break;
  477.  
  478.     case OP_POST_PLUS:
  479.         SetVariableValue (stack[StackPointer].lval,
  480.                    stack[StackPointer].val + 1);
  481.         break;
  482.  
  483.     case OP_POST_MINUS:
  484.         SetVariableValue (stack[StackPointer].lval,
  485.                    stack[StackPointer].val - 1);
  486.         break;
  487.  
  488.     case OP_UNARY_PLUS:
  489.         stack[StackPointer].lval= -1;
  490.         break;
  491.  
  492.     case OP_UNARY_MINUS:
  493.         stack[StackPointer].val = -stack[StackPointer].val;
  494.         stack[StackPointer].lval= -1;
  495.         break;
  496.  
  497.     case OP_BINARY_AND_EQUALS:
  498.         POP_2_VALUES ();
  499.         PUSH_VALUE_ON_STACK (a & b);
  500.         break;
  501.  
  502.     case OP_BINARY_XOR_EQUALS:
  503.         POP_2_VALUES ();
  504.         PUSH_VALUE_ON_STACK (a ^ b);
  505.         break;
  506.  
  507.     case OP_BINARY_OR_EQUALS:
  508.         POP_2_VALUES ();
  509.         PUSH_VALUE_ON_STACK (a | b);
  510.         break;
  511.  
  512.     case OP_MULTIPLY:
  513.         POP_2_VALUES ();
  514.         PUSH_VALUE_ON_STACK (a * b);
  515.         break;
  516.  
  517.     case OP_DIVIDE:
  518.         POP_2_VALUES ();
  519.  
  520.         if (CheckNotZero (b))
  521.          PUSH_VALUE_ON_STACK (a / b);
  522.  
  523.         break;
  524.  
  525.     case OP_MODULUS:
  526.         POP_2_VALUES ();
  527.  
  528.         if (CheckNotZero (b))
  529.         PUSH_VALUE_ON_STACK (a % b);
  530.  
  531.         break;
  532.  
  533.     case OP_PLUS:
  534.         POP_2_VALUES ();
  535.         PUSH_VALUE_ON_STACK (a + b);
  536.         break;
  537.  
  538.     case OP_MINUS:
  539.         POP_2_VALUES ();
  540.         PUSH_VALUE_ON_STACK (a - b);
  541.         break;
  542.  
  543.     case OP_SHIFT_LEFT:
  544.         POP_2_VALUES ();
  545.         PUSH_VALUE_ON_STACK (a  <<  b);
  546.         break;
  547.  
  548.     case OP_SHIFT_RIGHT:
  549.         POP_2_VALUES ();
  550.         PUSH_VALUE_ON_STACK (a >> b);
  551.         break;
  552.  
  553.     case OP_LESS:
  554.         POP_2_VALUES ();
  555.         PUSH_VALUE_ON_STACK (a < b);
  556.         break;
  557.  
  558.     case OP_LESS_EQUALS:
  559.         POP_2_VALUES ();
  560.         PUSH_VALUE_ON_STACK (a <= b);
  561.         break;
  562.  
  563.     case OP_GREATER:
  564.         POP_2_VALUES ();
  565.         PUSH_VALUE_ON_STACK (a > b);
  566.         break;
  567.  
  568.     case OP_GREATER_EQUALS:
  569.         POP_2_VALUES ();
  570.         PUSH_VALUE_ON_STACK (a >= b);
  571.         break;
  572.  
  573.     case OP_EQUALS:
  574.         POP_2_VALUES ();
  575.         PUSH_VALUE_ON_STACK (a == b);
  576.         break;
  577.  
  578.     case OP_NOT_EQUALS:
  579.         POP_2_VALUES ();
  580.         PUSH_VALUE_ON_STACK (a != b);
  581.         break;
  582.  
  583.     case OP_LOGICAL_AND_EQUALS:
  584.         POP_2_VALUES ();
  585.         PUSH_VALUE_ON_STACK (a && b);
  586.         break;
  587.  
  588.     case OP_LOGICAL_OR_EQUALS:
  589.         POP_2_VALUES ();
  590.         PUSH_VALUE_ON_STACK (a || b);
  591.         break;
  592.  
  593.     case OP_LOGICAL_XOR_EQUALS:
  594.         POP_2_VALUES ();
  595.         PUSH_VALUE_ON_STACK ((a && !b) || (!a && b));
  596.         break;
  597.  
  598.     case OP_QUESTION_MARK:
  599.         c = stack[StackPointer--].val;
  600.         POP_2_VALUES ();
  601.  
  602.         PUSH_VALUE_ON_STACK ((a) ? b : c);
  603.         break;
  604.  
  605.     case OP_COLON:
  606.         break;
  607.  
  608.     case OP_SET:
  609.         POP_2_VALUES ();
  610.         lv = stack[StackPointer + 1].lval;
  611.         SET_VALUE_ON_STACK (b);
  612.         break;
  613.  
  614.     case OP_PLUS_EQUAL:
  615.         POP_2_VALUES ();
  616.         lv = stack[StackPointer + 1].lval;
  617.         SET_VALUE_ON_STACK (a + b);
  618.         break;
  619.  
  620.     case OP_MINUS_EQUAL:
  621.         POP_2_VALUES ();
  622.         lv = stack[StackPointer + 1].lval;
  623.         SET_VALUE_ON_STACK (a - b);
  624.         break;
  625.  
  626.     case OP_MULTIPLY_EQUAL:
  627.         POP_2_VALUES ();
  628.         lv = stack[StackPointer + 1].lval;
  629.         SET_VALUE_ON_STACK (a * b);
  630.         break;
  631.  
  632.     case OP_DIVIDE_EQUAL:
  633.         POP_2_VALUES ();
  634.         lv = stack[StackPointer + 1].lval;
  635.  
  636.         if (CheckNotZero (b))
  637.         SET_VALUE_ON_STACK (a / b);
  638.  
  639.         break;
  640.  
  641.     case OP_MODULUS_EQUAL:
  642.         POP_2_VALUES ();
  643.         lv = stack[StackPointer + 1].lval;
  644.  
  645.         if (CheckNotZero (b))
  646.          SET_VALUE_ON_STACK (a % b);
  647.  
  648.         break;
  649.  
  650.     case OP_BINARY_AND_SET:
  651.         POP_2_VALUES ();
  652.         lv = stack[StackPointer + 1].lval;
  653.         SET_VALUE_ON_STACK (a & b);
  654.         break;
  655.  
  656.     case OP_BINARY_XOR_SET:
  657.         POP_2_VALUES ();
  658.         lv = stack[StackPointer + 1].lval;
  659.         SET_VALUE_ON_STACK (a ^ b);
  660.         break;
  661.  
  662.     case OP_BINARY_OR_SET:
  663.         POP_2_VALUES ();
  664.         lv = stack[StackPointer + 1].lval;
  665.         SET_VALUE_ON_STACK (a | b);
  666.         break;
  667.  
  668.     case OP_SHIFT_LEFT_EQUAL:
  669.         POP_2_VALUES ();
  670.         lv = stack[StackPointer + 1].lval;
  671.         SET_VALUE_ON_STACK (a << b);
  672.         break;
  673.  
  674.     case OP_SHIFT_RIGHT_EQUAL:
  675.         POP_2_VALUES ();
  676.         lv = stack[StackPointer + 1].lval;
  677.         SET_VALUE_ON_STACK (a >> b);
  678.         break;
  679.  
  680.     case OP_LOGICAL_AND_SET:
  681.         POP_2_VALUES ();
  682.         lv = stack[StackPointer + 1].lval;
  683.         SET_VALUE_ON_STACK (a && b);
  684.         break;
  685.  
  686.     case OP_LOGICAL_OR_SET:
  687.         POP_2_VALUES ();
  688.         lv = stack[StackPointer + 1].lval;
  689.         SET_VALUE_ON_STACK (a || b);
  690.         break;
  691.  
  692.     case OP_LOGICAL_XOR_SET:
  693.         POP_2_VALUES ();
  694.         lv = stack[StackPointer + 1].lval;
  695.         SET_VALUE_ON_STACK ((a && !b) || (!a && b));
  696.         break;
  697.  
  698.     case OP_COMMA:
  699.         POP_2_VALUES ();
  700.         PUSH_VALUE_ON_STACK (b);
  701.         break;
  702.  
  703.     case OP_PRE_PLUS:
  704.         stack[StackPointer].val =
  705.         SetVariableValue (stack[StackPointer].lval,
  706.                   stack[StackPointer].val + 1);
  707.         break;
  708.  
  709.     case OP_PRE_MINUS:
  710.         stack[StackPointer].val =
  711.         SetVariableValue (stack[StackPointer].lval,
  712.                   stack[StackPointer].val - 1);
  713.         break;
  714.  
  715.     default:
  716.         ShellErrorMessage ("out of integers");
  717.         ExpansionErrorDetected = TRUE;
  718.         return;
  719.     }
  720. }
  721.  
  722. /*
  723.  * Handle binary operators
  724.  */
  725.  
  726. static void near ProcessBinaryOperator (int tk)
  727. {
  728.     switch (tk)
  729.     {
  730.     case OP_LOGICAL_AND_EQUALS:
  731.     case OP_LOGICAL_AND_SET:
  732.         if (!stack[StackPointer].val)
  733.         JustParsing++;
  734.  
  735.         break;
  736.  
  737.     case OP_LOGICAL_OR_EQUALS:
  738.     case OP_LOGICAL_OR_SET:
  739.         if (stack[StackPointer].val)
  740.         JustParsing++;
  741.  
  742.         break;
  743.     }
  744. }
  745.  
  746. /*
  747.  * Common processing
  748.  */
  749.  
  750. long EvaluateMathsExpression (char *s)
  751. {
  752.     int        i;
  753.  
  754.     for (i = 0; i != MAX_VARIABLES; i++)
  755.     ListOfVariableNames[i] = (char *)NULL;
  756.  
  757.     LastNumberBase = -1;        /* Reset base            */
  758.     NumberOfVariables = 0;
  759.     CStringp = s;
  760.     StackPointer = -1;
  761.     RecogniseUnaryOperator = TRUE;
  762.     ParseMathsExpression (MAX_PRECEDENCE);
  763.  
  764.     if (StackPointer)
  765.     {
  766.     ShellErrorMessage ("bad math expression - unbalanced stack");
  767.     ExpansionErrorDetected = TRUE;
  768.     }
  769.  
  770.     if (*CStringp)
  771.     {
  772.     ShellErrorMessage ("bad math expression - illegal character: %c",
  773.                *CStringp);
  774.     ExpansionErrorDetected = TRUE;
  775.     }
  776.  
  777.     for (i = 0; i != NumberOfVariables; i++)
  778.     ReleaseMemoryCell ((void *)ListOfVariableNames[i]);
  779.  
  780.     return stack[0].val;
  781. }
  782.  
  783. /*
  784.  * operator-precedence parse the string and execute
  785.  */
  786.  
  787. static void near ParseMathsExpression (int pc)
  788. {
  789.     LastToken = MathsLexicalAnalyser ();
  790.  
  791.     while (Operators[LastToken].Precedences <= pc)
  792.     {
  793.     if (LastToken == OP_NUMERIC_VALUE)
  794.         PushOnToStack (yyval, -1);
  795.  
  796.     else if (LastToken == OP_VARIABLE)
  797.         PushOnToStack (GetVariableAsNumeric (ListOfVariableNames[yylval]),
  798.                yylval);
  799.  
  800.     else if (LastToken == OP_OPEN_PAR)
  801.     {
  802.         ParseMathsExpression (MAX_PRECEDENCE);
  803.  
  804.         if (LastToken != OP_CLOSE_PAR)
  805.         {
  806.         ShellErrorMessage ("unmatched ()'s");
  807.         return;
  808.         }
  809.     }
  810.  
  811.     else if (LastToken == OP_QUESTION_MARK)
  812.     {
  813.         long    q = stack[StackPointer].val;
  814.  
  815.         if (!q)
  816.         JustParsing++;
  817.  
  818.         ParseMathsExpression (Operators[OP_QUESTION_MARK].Precedences - 1);
  819.  
  820.         if (!q)
  821.         JustParsing--;
  822.  
  823.         else
  824.         JustParsing++;
  825.  
  826.         ParseMathsExpression (Operators[OP_QUESTION_MARK].Precedences);
  827.  
  828.         if (q)
  829.         JustParsing--;
  830.  
  831.         ProcessOperator (OP_QUESTION_MARK);
  832.         continue;
  833.     }
  834.  
  835.     else
  836.     {
  837.         int        otok = LastToken;
  838.         int        onoeval = JustParsing;
  839.  
  840.         if (Operators[otok].Type == BOOL_A)
  841.         ProcessBinaryOperator (otok);
  842.  
  843.         ParseMathsExpression (Operators[otok].Precedences -
  844.                   (Operators[otok].Type != RIGHT_LEFT_A));
  845.         JustParsing = onoeval;
  846.         ProcessOperator (otok);
  847.         continue;
  848.     }
  849.  
  850.     LastToken = MathsLexicalAnalyser ();
  851.     }
  852. }
  853.  
  854. /*
  855.  * Decide on 'op=', 'opop' or 'op'
  856.  */
  857.  
  858. static int near DecideDoubleOperator (char op, int dequal, int equal,
  859.                       int twice, int single)
  860. {
  861.     RecogniseUnaryOperator = TRUE;
  862.  
  863.     if (*CStringp == op)
  864.     {
  865.     if (*(++CStringp) == '=')
  866.     {
  867.         CStringp++;
  868.         return dequal;
  869.     }
  870.  
  871.     return twice;
  872.     }
  873.  
  874.     else if (*CStringp == '=')
  875.     {
  876.     CStringp++;
  877.     return equal;
  878.     }
  879.  
  880.     return single;
  881. }
  882.  
  883. /*
  884.  * Decide on single operator 'op' or 'op='
  885.  */
  886.  
  887. static int near DecideSingleOperator (int equal, int single)
  888. {
  889.     RecogniseUnaryOperator = TRUE;
  890.  
  891.     if (*CStringp != '=')
  892.     return single;
  893.  
  894.     CStringp++;
  895.     return equal;
  896. }
  897.  
  898. /*
  899.  * Handle +=, ++, + or -=, --, -
  900.  */
  901.  
  902. static int near DecideSignOperator (char sign, int pre_op, int post_op,
  903.                     int equals, int unary_op, int op)
  904. {
  905.     if ((*CStringp == sign) && (RecogniseUnaryOperator || !isalnum (*CStringp)))
  906.     {
  907.     CStringp++;
  908.     return RecogniseUnaryOperator ? pre_op : post_op;
  909.     }
  910.  
  911.     if (*CStringp == '=')
  912.     {
  913.     RecogniseUnaryOperator = TRUE;
  914.     CStringp++;
  915.     return equals;
  916.     }
  917.  
  918.     return RecogniseUnaryOperator ? unary_op : op;
  919. }
  920.  
  921. /*
  922.  * Validate maths expression without the error message generated a
  923.  * command.  This forces the processing to drop down the stack rather than
  924.  * doing a deep-exit on error.
  925.  */
  926.  
  927. bool ValidMathsExpression (char *string, long *value)
  928. {
  929.     int     *Save_ERP = e.ErrorReturnPoint;
  930.     bool    Save_EED = ExpansionErrorDetected;
  931.     bool    Result;
  932.  
  933. /* save the environment */
  934.  
  935.     e.ErrorReturnPoint = NULL;
  936.     ExpansionErrorDetected = FALSE;
  937.  
  938. /* Validate the number */
  939.  
  940.     *value = EvaluateMathsExpression (string);
  941.     Result = ExpansionErrorDetected;
  942.  
  943. /* Restore environment */
  944.  
  945.     e.ErrorReturnPoint = Save_ERP;
  946.     ExpansionErrorDetected = Save_EED;
  947.     return Result;
  948. }
  949.